import type { ReactiveEffect } from './effect'
import { warn } from './warning'

export let activeEffectScope: EffectScope | undefined

export class EffectScope {
  /**
   * @internal
   */
  /**
   * @internal
   * 标识当前作用域是否处于激活状态
   * 当作用域被停止(stop)后变为false
   */
  private _active = true
  
  /**
   * @internal
   * 跟踪作用域的激活次数，用于嵌套激活控制
   * 通过on/off方法进行增减，归零时恢复父作用域
   */
  private _on = 0
  
  /**
   * @internal
   * 存储当前作用域管理的所有响应式副作用(effects)
   * 当作用域停止时会自动停止所有关联的副作用
   */
  effects: ReactiveEffect[] = []
  
  /**
   * @internal
   * 清理函数集合，通过onScopeDispose注册
   * 作用域停止时会按注册顺序执行所有清理函数
   */
  cleanups: (() => void)[] = []

  /**
   * @internal
   * 暂停状态标识，用于临时暂停作用域内所有副作用的响应
   * 通过pause()/resume()方法控制状态切换
   */
  private _isPaused = false

  /**
   * @internal
   * 父级作用域引用(仅限非独立作用域)
   * 用于维护作用域层级结构，停止时会自动从父作用域移除
   */
  parent: EffectScope | undefined
  
  /**
   * @internal
   * 子作用域集合(仅限非独立作用域)
   * 维护当前作用域直接嵌套的子作用域列表
   */
  scopes: EffectScope[] | undefined
  
  /**
   * @internal
   * 在父作用域scopes数组中的索引位置
   * 用于在移除操作时实现O(1)时间复杂度
   */
  private index: number | undefined

  /**
   * 创建新的作用域实例
   * @param detached 是否为独立作用域：
   *   - true: 独立作用域，不自动关联父作用域
   *   - false: 非独立作用域，自动维护父子关系
   */
  constructor(public detached = false) {
    // 建立父子作用域关系
    this.parent = activeEffectScope
    
    // 非独立作用域需要注册到父作用域
    if (!detached && activeEffectScope) {
      // 优化子作用域管理：
      // 1. 使用数组存储保证顺序
      // 2. 记录当前索引实现快速删除
      this.index =
        (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
          this,
        ) - 1
    }
  }

  get active(): boolean {
    return this._active
  }

  /**
   * 暂停作用域内所有副作用响应
   * 递归暂停所有子作用域和关联的副作用
   * 注意：暂停状态不影响作用域激活状态
   */
  pause(): void {
    if (this._active) {
      this._isPaused = true
      let i, l
      // 深度优先暂停子作用域
      if (this.scopes) {
        for (i = 0, l = this.scopes.length; i < l; i++) {
          this.scopes[i].pause()
        }
      }
      // 暂停当前作用域的所有副作用
      for (i = 0, l = this.effects.length; i < l; i++) {
        this.effects[i].pause()
      }
    }
  }

  /**
   * 恢复作用域内所有副作用响应
   * 递归恢复所有子作用域和关联的副作用
   * 要求作用域必须处于激活状态
   */
  resume(): void {
    if (this._active) {
      if (this._isPaused) {
        this._isPaused = false
        let i, l
        // 深度优先恢复子作用域
        if (this.scopes) {
          for (i = 0, l = this.scopes.length; i < l; i++) {
            this.scopes[i].resume()
          }
        }
        // 恢复当前作用域的所有副作用
        for (i = 0, l = this.effects.length; i < l; i++) {
          this.effects[i].resume()
        }
      }
    }
  }

  run<T>(fn: () => T): T | undefined {
    if (this._active) {
      const currentEffectScope = activeEffectScope
      try {
        activeEffectScope = this
        return fn()
      } finally {
        activeEffectScope = currentEffectScope
      }
    } else if (__DEV__) {
      warn(`cannot run an inactive effect scope.`)
    }
  }

  prevScope: EffectScope | undefined
  /**
   * 此方法仅应在非独立作用域上调用
   * @internal
   */
  on(): void {
    if (++this._on === 1) {
      this.prevScope = activeEffectScope
      activeEffectScope = this
    }
  }

  /**
   * 此方法仅应在非独立作用域上调用
   * @internal
   */
  off(): void {
    if (this._on > 0 && --this._on === 0) {
      activeEffectScope = this.prevScope
      this.prevScope = undefined
    }
  }

  /**
   * 停止当前作用域及其所有子作用域
   * @param fromParent 标识是否由父作用域触发停止
   *   防止循环调用和重复清理
   */
  stop(fromParent?: boolean): void {
    if (this._active) {
      this._active = false
      
      // 停止所有关联的副作用
      let i, l
      for (i = 0, l = this.effects.length; i < l; i++) {
        this.effects[i].stop()
      }
      this.effects.length = 0

      // 执行所有清理函数
      for (i = 0, l = this.cleanups.length; i < l; i++) {
        this.cleanups[i]()
      }
      this.cleanups.length = 0

      // 递归停止所有子作用域
      if (this.scopes) {
        for (i = 0, l = this.scopes.length; i < l; i++) {
          this.scopes[i].stop(true)
        }
        this.scopes.length = 0
      }

      // 从父作用域中移除当前作用域（仅限非独立作用域）
      if (!this.detached && this.parent && !fromParent) {
        // 优化移除算法：
        // 1. 取出最后一个子作用域
        // 2. 如果被移除项不是最后一个，则交换位置
        // 3. 更新交换项索引，保持O(1)时间复杂度
        const last = this.parent.scopes!.pop()
        if (last && last !== this) {
          this.parent.scopes![this.index!] = last
          last.index = this.index!
        }
      }
      
      // 断开父子引用，防止内存泄漏
      this.parent = undefined
    }
  }
}

/**
 * 创建一个副作用作用域对象，该对象可以捕获在其内部创建的响应式副作用（例如计算属性和监听器），以便这些副作用可以一起被销毁。
 * 有关此API的详细用例，请参考其对应的 {@link https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md | RFC}。
 *
 * @param detached - 可用于创建一个“独立”的副作用作用域。
 * @see {@link https://vuejs.org/api/reactivity-advanced.html#effectscope}
 */
export function effectScope(detached?: boolean): EffectScope {
  return new EffectScope(detached)
}

/**
 * 如果存在当前活动的副作用作用域，则返回该作用域。
 *
 * @see {@link https://vuejs.org/api/reactivity-advanced.html#getcurrentscope}
 */
export function getCurrentScope(): EffectScope | undefined {
  return activeEffectScope
}

/**
 * 在当前活动的副作用作用域上注册一个销毁回调函数。
 * 当关联的副作用作用域停止时，该回调函数将被调用。
 *
 * @param fn - 要附加到作用域清理操作的回调函数。
 * @see {@link https://vuejs.org/api/reactivity-advanced.html#onscopedispose}
 */
export function onScopeDispose(fn: () => void, failSilently = false): void {
  if (activeEffectScope) {
    activeEffectScope.cleanups.push(fn)
  } else if (__DEV__ && !failSilently) {
    warn(
      `onScopeDispose() is called when there is no active effect scope` +
        ` to be associated with.`,
    )
  }
}
